home *** CD-ROM | disk | FTP | other *** search
/ Apple Developer Connection Student Program / ADC Tools Sampler CD Disk 3 1999.iso / Metrowerks CodeWarrior / Java Support / Java_Source / IFC_112 / netscape / application / Alert.java next >
Encoding:
Text File  |  1999-05-28  |  16.1 KB  |  431 lines  |  [TEXT/CWIE]

  1. // Alert.java
  2. // By Ned Etcode
  3. // Copyright 1995, 1996, 1997 Netscape Communications Corp.  All rights reserved.
  4.  
  5. package netscape.application;
  6.  
  7. import netscape.util.*;
  8.  
  9. /** Object subclass containing a collection of static methods that create an
  10.   * "Alert": a modal Window presenting the user with
  11.   * a simple question with up to three possible answers. When run, an
  12.   * InternalWindow or ExternalWindow appears, centered, that will not
  13.   * disappear until the user clicks one of the three answer Buttons.
  14.   * @note 1.0 ...image() calls returned cached bitmap instead of new one each
  15.   *           time.
  16.   * @note 1.1 minor drawing bug fixed
  17.   */
  18.  
  19. public class Alert {
  20.     /** Value returned when the user chooses the default option. */
  21.     public final static int DEFAULT_OPTION = 1;
  22.  
  23.     /** Value returned when the user chooses the 2nd option. */
  24.     public final static int SECOND_OPTION = 2;
  25.  
  26.     /** Value returned when the user chooses the 3rd option. */
  27.     public final static int THIRD_OPTION = 3;
  28.  
  29.  
  30.     private final int MIN_WIDTH          =  200;
  31.     private final int WIDTH_MARGIN       =  7;
  32.     private final int TOP_MARGIN         =  8;
  33.     private final int BOTTOM_MARGIN      =  8;
  34.     private final int TEXT_TOP_MARGIN    =  0;
  35.     private final int TEXT_BOTTOM_MARGIN =  3;
  36.     private final int BUTTON_HORIZ_MARGIN = 6;
  37.     private final int TITLE_LEFT_MARGIN   = 3;
  38.     private final float BUTTON_CENTER_RATIO = ((float)2/(float)3);
  39.  
  40.     static  final String DEFAULT_ACTION="performDefaultAction";
  41.     static  final String SECOND_ACTION="performSecondAction";
  42.     static  final String THIRD_ACTION="performThirdAction";
  43.     private final int    MIN_BUTTON_WIDTH=50;
  44.  
  45.     private Window window;
  46.     private AlertContentView  contentView;
  47.     private TextField titleTextField;
  48.     private TextView  messageTextView;
  49.     private Button defaultButton,secondButton,thirdButton;
  50.     private int result;
  51.     private Button bitmapContainer;
  52.  
  53.  
  54.  
  55.     /** Return an image for a notification */
  56.     public static Image notificationImage() {
  57.         return Bitmap.bitmapNamed("netscape/application/alertNotification.gif");
  58.     }
  59.  
  60.     /** Return an image for a question */
  61.     public static Image questionImage() {
  62.         return Bitmap.bitmapNamed("netscape/application/alertQuestion.gif");
  63.     }
  64.  
  65.     /** Return an image for a warning */
  66.     public static Image warningImage() {
  67.         return Bitmap.bitmapNamed("netscape/application/alertWarning.gif");
  68.     }
  69.  
  70.     /** Runs an Alert using an InternalWindow. <b>title</b> is the
  71.       * Alert's title and <b>message</b> is the message that
  72.       * should be displayed.  <b>defaultOption</b>, <b>secondOption</b> and
  73.       * <b>thirdOption</b> are the Alert's Button titles. If
  74.       * <b>secondOption</b> or <b>thirdOption</b> are <b>null</b>, their
  75.       * Buttons will not appear.  Returns the Button the user clicked.
  76.       * This method does not return until the user clicks a Button.
  77.       */
  78.     public static int runAlertInternally(String title,
  79.                         String message, String defaultOption,
  80.                         String secondOption, String thirdOption) {
  81.         return runAlertInternally(null,title,message,defaultOption,
  82.                            secondOption,thirdOption);
  83.     }
  84.  
  85.     /** Runs an Alert using an ExternalWindow. <b>title</b> is the
  86.       * Alert's title and <b>message</b> is the message that
  87.       * should be displayed.  <b>defaultOption</b>, <b>secondOption</b> and
  88.       * <b>thirdOption</b> are the Alert's Button titles. If
  89.       * <b>secondOption</b> or <b>thirdOption</b> are <b>null</b>, their
  90.       * Buttons will not appear.  Returns the Button the user clicked.
  91.       * This method does not return until the user clicks a Button.
  92.       */
  93.     public static int runAlertExternally(String title,
  94.                         String message, String defaultOption,
  95.                         String secondOption, String thirdOption) {
  96.         return runAlertExternally(null,title,message,defaultOption,
  97.                            secondOption,thirdOption);
  98.     }
  99.  
  100.     /** Runs an alert using an InternalWindow. <b>image</b> is the Image
  101.       * displayed near the title. <b>title</b> is the
  102.       * Alert's title and <b>message</b> is the message that
  103.       * should be displayed.  <b>defaultOption</b>, <b>secondOption</b> and
  104.       * <b>thirdOption</b> are the Alert's Button titles. If
  105.       * <b>secondOption</b> or <b>thirdOption</b> are <b>null</b>, their
  106.       * Buttons will not appear.  Returns the Button the user clicked.
  107.       * This method does not return until the user clicks a Button.
  108.       */
  109.     public static int runAlertInternally(Image image, String title,
  110.                         String message, String defaultOption,
  111.                         String secondOption, String thirdOption) {
  112.         Alert alert = new Alert( title,
  113.                                  message,
  114.                                  defaultOption,
  115.                                  secondOption,
  116.                                  thirdOption);
  117.         alert.setImage(image);
  118.         return alert.run(false);
  119.     }
  120.  
  121.     /** Runs an Alert using an ExternalWindow. <b>image</b> is the Image
  122.       * displayed near the title. <b>title</b> is the
  123.       * Alert's title and <b>message</b> is the message that
  124.       * should be displayed.  <b>defaultOption</b>, <b>secondOption</b> and
  125.       * <b>thirdOption</b> are the Alert's Button titles. If
  126.       * <b>secondOption</b> or <b>thirdOption</b> are <b>null</b>, their
  127.       * Buttons will not appear.  Returns the Button the user clicked.
  128.       * This method does not return until the user clicks a Button.
  129.       */
  130.     public static int runAlertExternally(Image image, String title,
  131.                         String message, String defaultOption,
  132.                         String secondOption, String thirdOption) {
  133.         Alert alert = new Alert( title,
  134.                                  message,
  135.                                  defaultOption,
  136.                                  secondOption,
  137.                                  thirdOption);
  138.         alert.setImage(image);
  139.         return alert.run(true);
  140.     }
  141.  
  142.  
  143.     /** Creates an alert. Negative option and alternateOption are optional and
  144.       * can be null.
  145.       */
  146.     private Alert(String title, String message, String positiveOption,
  147.                  String negativeOption,String alternateOption) {
  148.         super();
  149.         Size sz;
  150.         Hashtable defaultAttributes;
  151.         TextParagraphFormat format;
  152.  
  153.         contentView = new AlertContentView(this,0,0,100,100);
  154.         contentView.setVertResizeInstruction(View.HEIGHT_CAN_CHANGE);
  155.         contentView.setHorizResizeInstruction(View.WIDTH_CAN_CHANGE);
  156.  
  157.         bitmapContainer = new Button(0,0,100,100);
  158.         bitmapContainer.setEnabled(false);
  159.         bitmapContainer.setBordered(false);
  160.  
  161.         sz = bitmapContainer.minSize();
  162.         bitmapContainer.sizeTo(sz.width,sz.height);
  163.         contentView.addSubview(bitmapContainer);
  164.  
  165.         titleTextField = new TextField(0,0,100,0);
  166.         titleTextField.setFont(new Font(Font.defaultFont().name(), Font.BOLD,
  167.                                18));
  168.         titleTextField.setJustification(Graphics.LEFT_JUSTIFIED);
  169.         titleTextField.setStringValue(title);
  170.         titleTextField.setBorder(null);
  171.         titleTextField.setBackgroundColor(Color.lightGray);
  172.         titleTextField.setEditable(false);
  173.         contentView.addSubview(titleTextField);
  174.  
  175.  
  176.         messageTextView  = new TextView(0,0,100,20);
  177.         messageTextView.setEditable(false);
  178.         messageTextView.setSelectable(false);
  179.         messageTextView.setString("\n" + message + "\n");
  180.         messageTextView.setBackgroundColor(Color.lightGray);
  181.         defaultAttributes = messageTextView.defaultAttributes();
  182.         format = (TextParagraphFormat) defaultAttributes.get(TextView.PARAGRAPH_FORMAT_KEY);
  183.         defaultAttributes = (Hashtable) defaultAttributes.clone();
  184.         format = (TextParagraphFormat) format.clone();
  185.         format.setLeftMargin(0);
  186.         format.setLeftIndent(0);
  187.         format.setRightMargin(0);
  188.         defaultAttributes.put(TextView.PARAGRAPH_FORMAT_KEY, format);
  189.         messageTextView.setDefaultAttributes(defaultAttributes);
  190.         contentView.addSubview(messageTextView);
  191.  
  192.  
  193.         defaultButton = new Button(0,0,100,20);
  194.         defaultButton.setTitle(positiveOption);
  195.         defaultButton.setTarget(contentView);
  196.         defaultButton.setCommand(DEFAULT_ACTION);
  197.         contentView.addSubview(defaultButton);
  198.  
  199.         if( negativeOption != null ) {
  200.             secondButton = new Button(0,0,100,20);
  201.             secondButton.setTitle(negativeOption);
  202.             secondButton.setTarget(contentView);
  203.             secondButton.setCommand(SECOND_ACTION);
  204.             contentView.addSubview(secondButton);
  205.         }
  206.  
  207.         if( alternateOption != null ) {
  208.             thirdButton = new Button(0,0,100,20);
  209.             thirdButton.setTitle(alternateOption);
  210.             thirdButton.setTarget(contentView);
  211.             thirdButton.setCommand(THIRD_ACTION);
  212.             contentView.addSubview(thirdButton);
  213.         }
  214.  
  215.     }
  216.  
  217.     private void setImage(Image anImage) {
  218.         Size sz;
  219.  
  220.         bitmapContainer.setImage(anImage);
  221.         sz = bitmapContainer.minSize();
  222.         bitmapContainer.sizeTo(sz.width,sz.height);
  223.     }
  224.  
  225.     private void calculateLayout() {
  226.         FontMetrics fm;
  227.         int buttonRowWidth;
  228.         int minWidth = MIN_WIDTH;
  229.         boolean centerButtons = false;
  230.         int centeredButtonSpacing = 0;
  231.         int buttonOffset = 0;
  232.  
  233.         /* Calculate the required width */
  234.  
  235.         /* Title */
  236.         fm = new FontMetrics(titleTextField.font());
  237.         minWidth =  max(minWidth,
  238.                         fm.stringWidth(titleTextField.stringValue()) +
  239.                         (2 * WIDTH_MARGIN) +
  240.                         TITLE_LEFT_MARGIN + bitmapContainer.width());
  241.         titleTextField.sizeTo(100,fm.stringHeight());
  242.  
  243.         /* Message */
  244.         Size reqSize  = requiredSizeToPreserveLinesInTextView(messageTextView);
  245.         minWidth =  max(minWidth, reqSize.width + (2 * WIDTH_MARGIN));
  246.         messageTextView.sizeTo(reqSize.width,reqSize.height);
  247.  
  248.  
  249.         /* Buttons */
  250.         Size buttonSize = new Size();
  251.         int buttonCount = 1;
  252.         fm = new FontMetrics(defaultButton.font());
  253.         buttonSize.width  = max(fm.stringWidth(defaultButton.title()) + 10,
  254.                                 MIN_BUTTON_WIDTH);
  255.         buttonSize.height = fm.stringHeight() + 4;
  256.  
  257.         if( secondButton != null ) {
  258.             buttonSize.width = max(buttonSize.width, fm.stringWidth(secondButton.title()) + 10);
  259.             buttonCount++;
  260.         }
  261.  
  262.         if( thirdButton != null ) {
  263.             buttonSize.width = max(buttonSize.width, fm.stringWidth(thirdButton.title()) + 10);
  264.             buttonCount++;
  265.         }
  266.  
  267.  
  268.         buttonRowWidth = (2 * WIDTH_MARGIN) + (buttonCount * buttonSize.width) +
  269.             (buttonCount-1) * BUTTON_HORIZ_MARGIN;
  270.         if( buttonRowWidth < minWidth &&
  271.             ((float)buttonRowWidth  / (float)minWidth) > BUTTON_CENTER_RATIO ) {
  272.  
  273.             buttonOffset = (minWidth - (buttonCount * buttonSize.width)) /
  274.                              (1 + buttonCount);
  275.             centeredButtonSpacing = (int)((double)buttonOffset * ((double)6/(double)7));
  276.             buttonOffset = (minWidth - (buttonCount * buttonSize.width) -
  277.                                       ((buttonCount-1) * centeredButtonSpacing)) / 2;
  278.             centerButtons = true;
  279.         } else {
  280.             centerButtons = false;
  281.             minWidth = max(minWidth,buttonRowWidth);
  282.         }
  283.  
  284.         /* Let's make the layout */
  285.         Rect rect = new Rect();
  286.  
  287.         /* Image  */
  288.         rect.x = WIDTH_MARGIN;
  289.         rect.y = TOP_MARGIN;
  290.         if( bitmapContainer.image() != null ) {
  291.             if( bitmapContainer.superview() == null )
  292.                 contentView.addSubview(bitmapContainer);
  293.             bitmapContainer.moveTo(rect.x,rect.y);
  294.         } else
  295.             bitmapContainer.removeFromSuperview();
  296.  
  297.         /* Title */
  298.  
  299.         if( bitmapContainer.image() != null ) {
  300.             rect.x += bitmapContainer.width() + TITLE_LEFT_MARGIN;
  301.             rect.y = TOP_MARGIN + bitmapContainer.height() -
  302.                 titleTextField.height() + fm.descent() + 1;
  303.         } else
  304.             rect.y = TOP_MARGIN;
  305.         rect.width  = minWidth - (2 * WIDTH_MARGIN) -
  306.             TITLE_LEFT_MARGIN - bitmapContainer.width();
  307.         rect.height = titleTextField.bounds.height;
  308.         titleTextField.setBounds(rect);
  309.         if((bitmapContainer.y() + bitmapContainer.height()) >
  310.             rect.y + rect.height )
  311.             rect.y = bitmapContainer.y() + bitmapContainer.height() + TEXT_TOP_MARGIN;
  312.         else
  313.             rect.y += (rect.height + TEXT_TOP_MARGIN);
  314.  
  315.         /* Message */
  316.         rect.x = WIDTH_MARGIN;
  317.         rect.width  = messageTextView.bounds.width;
  318.         rect.height = messageTextView.bounds.height;
  319.         messageTextView.setBounds(rect);
  320.         rect.y += rect.height + TEXT_BOTTOM_MARGIN;
  321.  
  322.  
  323.         /* Buttons */
  324.         if( centerButtons ) {
  325.             rect.x = buttonOffset;
  326.             rect.width = buttonSize.width;
  327.             rect.height = buttonSize.height;
  328.             defaultButton.setBounds(rect);
  329.             if( secondButton != null ) {
  330.                 rect.x += (rect.width + centeredButtonSpacing);
  331.                 secondButton.setBounds(rect);
  332.             }
  333.  
  334.             if( thirdButton != null ) {
  335.                 rect.x += (rect.width + centeredButtonSpacing);
  336.                 thirdButton.setBounds(rect);
  337.             }
  338.         } else {
  339.             rect.x = minWidth - (WIDTH_MARGIN + (buttonSize.width * buttonCount) +
  340.                                  (BUTTON_HORIZ_MARGIN * (buttonCount-1)));
  341.             rect.width = buttonSize.width;
  342.             rect.height = buttonSize.height;
  343.             defaultButton.setBounds(rect);
  344.             rect.x += buttonSize.width + BUTTON_HORIZ_MARGIN;
  345.             if( secondButton != null ) {
  346.                 secondButton.setBounds(rect);
  347.                 rect.x += buttonSize.width + BUTTON_HORIZ_MARGIN;
  348.             }
  349.  
  350.             if( thirdButton != null ) {
  351.                 thirdButton.setBounds(rect);
  352.             }
  353.         }
  354.  
  355.         Size sz = new Size();
  356.         sz.width = minWidth;
  357.         sz.height = rect.y + buttonSize.height + BOTTOM_MARGIN;
  358.         contentView.sizeTo(sz.width,sz.height);
  359.     }
  360.  
  361.  
  362.     /** Run the alert. If useExternalWindow is true, an external window
  363.       * will be used to display the alert. Otherwise, an internal window
  364.       * will be used.
  365.       */
  366.     private int run(boolean useExternalWindow) {
  367.         Size minSize;
  368.  
  369.         calculateLayout();
  370.  
  371.         if( useExternalWindow ) {
  372.             window = new ExternalWindow( Window.TITLE_TYPE);
  373.         } else {
  374.             InternalAlertBorder border;
  375.  
  376.             window = new InternalWindow();
  377.             border = new InternalAlertBorder((InternalWindow)window);
  378.             ((InternalWindow)window).setBorder(border);
  379.         }
  380.  
  381.         window.setResizable(false);
  382.         minSize = window.windowSizeForContentSize( contentView.bounds.width,
  383.                                             contentView.bounds.height);
  384.         window.sizeTo(minSize.width,minSize.height);
  385.         window.addSubview( contentView );
  386.         window.center();
  387.         window.showModally();
  388.         return result;
  389.     }
  390.  
  391.     private int max(int i,int j) {
  392.         if( i > j )
  393.             return i;
  394.         else
  395.             return j;
  396.     }
  397.  
  398.     private Size requiredSizeToPreserveLinesInTextView(TextView aTextView) {
  399.         FontMetrics fm = new FontMetrics(aTextView.font());
  400.         FastStringBuffer sb = new FastStringBuffer();
  401.         int i,c;
  402.         int maxLineWidth = 0;
  403.         char ch;
  404.         int lineCount=1;
  405.         for(i=0,c=aTextView.length() ; i < c ; i++ ) {
  406.             if((ch= aTextView.characterAt(i)) == '\n' ) {
  407.                 maxLineWidth = max( maxLineWidth , fm.stringWidth(sb.toString()));
  408.                 sb.truncateToLength(0);
  409.                 lineCount++;
  410.             } else
  411.                 sb.append(ch);
  412.         }
  413.  
  414.         if( sb.length() != 0 )
  415.             maxLineWidth = max(maxLineWidth, fm.stringWidth(sb.toString()));
  416.  
  417.         Size result = new Size();
  418.         result.width = maxLineWidth;
  419.         result.height = fm.stringHeight() * lineCount;
  420.         return result;
  421.     }
  422.  
  423.     void setResult(int aResult) {
  424.         result = aResult;
  425.     }
  426.  
  427.     void hide() {
  428.         window.hide();
  429.     }
  430. }
  431.